import React, {
  useCallback,
  useContext,
  useEffect,
  useImperativeHandle,
  useMemo,
  useRef,
  useState,
} from 'react';
import { getMessage, TextWidget } from '@inbiz/react';
import { Checkbox, Empty, PaginationProps, Spin, ConfigProvider } from 'antd';
import ResizeObserver from 'rc-resize-observer';
import { EllipsisOutlined } from '@ant-design/icons';
import cls from 'classnames';
import { hasAuth } from '@inbiz/basic/AuthForm';
import Pagination from '@inbiz/basic/Pagination'

import {
  useActionReducer,
  useCardTmpl,
  useColumnConfig,
  useFetchData,
  useFormatCardColumns,
  useFormatInnerActions,
  useInbizPrefixCls,
  useInitSearchRef,
  usePagination,
  usePrint,
  useRefreshData,
} from '../../hooks';
import {
  ActionConfigType,
  ItemData,
  PageInfo,
  TableCtxType,
  TablePreviewProps,
} from '../../interfaces';
import api from './api';
import { InBizTableCtx, InBizTableRefCtx, TableCtx } from '../../context';
import { builtInTmpl, TmplPlaceConfigKey, emptyArr } from '../../shared';
import TableTop from './TableTop';
import Search from './Search';
import TableModal from './TableModal';
import Actions, { DropDownActions } from './Actions';
import formatters from '../../formatters';
import PrintTable from './PrintTable';
import { InbizIcon } from '@inbiz/utils';
import { isTableInModal } from '../../util';
import { GlobalRegistry } from '@inbiz/core';
import { commonLang } from '@inbiz/utils';
export interface CardContentTmplProps {
  record: Record<string, any>;
  config: {
    title: ItemData;
    img: ItemData;
    dataItems: ItemData[];
  };
  tmplNodeId: string;
  actions: ActionConfigType[];
  cardsMap: Map<string, any>;
  checkboxNode: React.ReactNode;
  viewMode?:string;
}

interface CardHeaderProps {
  title: string;
  headerLabel?: string;
  img: string;
  tmplNodeId: string;
  cardsMap: Map<string, any>;
  actions: React.ReactNode;
  record: Record<string, any>;
  checkboxNode: React.ReactNode;
  viewMode?:string;
}

const CardHeader = (props: CardHeaderProps) => {
  const actionsPrefixCls = useInbizPrefixCls('card-actions');
  const headerTitlePrefixCls = useInbizPrefixCls('card-header-title');
  const checkboxPrefixCls = useInbizPrefixCls('card-header-checkbox');
  const {viewMode}=props
  const renderDefaultHeader = useMemo(() => {
    return (
      <>
        {props.checkboxNode && <span className={checkboxPrefixCls}>{props.checkboxNode}</span>}
        <span className={headerTitlePrefixCls} title={props?.title || props.headerLabel}>
          {props.title || props.headerLabel}
        </span>
        <span className={actionsPrefixCls} style={{display:viewMode=='look'?'none':'block'}}>{props.actions}</span>
      </>
    );
  }, [props.cardsMap, props.record,viewMode]);
  const renderDefault2Header = useMemo(() => {
    return (
      <>
        <span className={headerTitlePrefixCls} title={props?.title || props.headerLabel}>
          {props.title || props.headerLabel}
        </span>
        {props.checkboxNode}
      </>
    );
  }, [props.cardsMap, props.record]);
  const renderDefault3Header = useMemo(() => {
    return props.checkboxNode;
  }, [props.cardsMap]);
  return (
    <header
      style={
        props?.img
          ? {
            backgroundImage: `url(/Preview/GetOriginFile?fileid=${props.img}&deviceTypeName=pc&browserPlatform=2)`,
          }
          : {}
      }
    >
      {props.tmplNodeId === 'default' && renderDefaultHeader}
      {props.tmplNodeId === 'default2' && renderDefault2Header}
      {props.tmplNodeId === 'default3' && renderDefault3Header}
    </header>
  );
};

const CardContent = (props: CardContentTmplProps) => {
  const { record = {}, config, actions, cardsMap, tmplNodeId,viewMode } = props;
  const { formItems } = useColumnConfig();
  const dataItems = config?.dataItems?.sort((cur, next) => cur.order - next.order);
  const actionsNode = actions?.length ? (
    <DropDownActions actions={actions} data={record}>
      <EllipsisOutlined />
    </DropDownActions>
  ) : null;
  const prefixCls = useInbizPrefixCls(`card-${tmplNodeId}-content`);
  const actionsPrefixCls = useInbizPrefixCls(`card-${tmplNodeId}-actions`);
  const actionsLinePrefixCls = useInbizPrefixCls(`card-${tmplNodeId}-actions-line`);
  const contentCheckPrefixCls = useInbizPrefixCls('card-content-checked');
  const boxPrefixCls = useInbizPrefixCls('card-data-box');
  const itemsPrefixCls = useInbizPrefixCls('card-data-items');
  const itemPrefixCls = useInbizPrefixCls('card-data-item');
  const itemChildrenPrefixCls = useInbizPrefixCls('card-data-item-children');

  return (
    <div
      className={
        cardsMap.has(record?.id) ? cls([prefixCls, contentCheckPrefixCls]) : cls([prefixCls])
      }
      style={{boxShadow:viewMode=='look'?'none': ''}}
    >
      <CardHeader
        title={formatters.removeHtmlTag(record[config.title.propName])}
        headerLabel={config.title.label}
        img={record[config.img.propName]}
        tmplNodeId={tmplNodeId}
        actions={actionsNode}
        cardsMap={cardsMap}
        record={record}
        checkboxNode={props.checkboxNode}
        viewMode={viewMode}
      />
      <div className={boxPrefixCls}>
        <main>
          <div className={itemsPrefixCls}>
            {dataItems.map((item) => {
              let propName = '';
              if (item?.children && item?.children.length > 0) {
                const cache: string[] = [];
                item.children.forEach((data) => {
                  cache.push(
                    data.label
                      ? `${getMessage(data.label)}: ${formatters.removeHtmlTag(record[data.propName])}`
                      : formatters.removeHtmlTag(record[data.propName]),
                  );
                });
                propName = cache.join(',');
              } else {
                propName = formatters.removeHtmlTag(record[item.propName]);
              }
              return (
                <div
                  key={`${item.id}`}
                  className={
                    item?.children && item?.children?.length
                      ? cls([itemPrefixCls, itemChildrenPrefixCls])
                      : cls([itemPrefixCls])
                  }
                >
                  {item?.label && (
                    <label title={getMessage(item.label)}>
                      <TextWidget>{item.label}</TextWidget>：
                    </label>
                  )}
                  <span title={propName}>{propName}</span>
                </div>
              );
            })}
          </div>
        </main>
        {tmplNodeId !== 'default' && (
          <div
            className={
              formItems.inLineBtnShow !== 'icon'
                ? cls([actionsPrefixCls, actionsLinePrefixCls])
                : cls([actionsPrefixCls])
            }
          >
            <Actions actions={actions} data={record} displayQty={actions.length > 3 ? 2 : 3} />
          </div>
        )}
      </div>
    </div>
  );
};

const TableCard: React.ForwardRefRenderFunction<any, TablePreviewProps> = (props, ref) => {
  const { autoLoad, thumbnail, showPage, pageRefresh, rowSelection, emit, height = 0, showHeightRule, boxPadding = 0, boxMargin = 0 } =
    useContext(InBizTableCtx);
  const { searchRef, eventsRef, inbizTableRef } = useContext(InBizTableRefCtx);
  let attrs: any;
  let tmpl: any;
  const { attrs: cardAttrs = [], thumbAttrs, formItems, thumbFormItems } = useColumnConfig();
  const { cardTmpl } = formItems;
  const { cardTmpl: thumbCardTmpl } = thumbFormItems;
  if (thumbnail) {
    tmpl = thumbCardTmpl;
    attrs = thumbAttrs;
  } else {
    tmpl = cardTmpl;
    attrs = cardAttrs;
  }
  const {viewMode}=props

  const { tmplNode } = useCardTmpl(tmpl);
  useInitSearchRef();
  const modalRef = useRef<any>({});
  const tableCacheRef = useRef<any>({ data: [] });
  const cardBoxRef = useRef<HTMLDivElement>(null);
  const boxPrefixCls = useInbizPrefixCls(`card-box`);
  const listPrefixCls = useInbizPrefixCls('card-list');
  const emptyDivPrefixCls = useInbizPrefixCls('card-content-empty-div');
  const { loading, pageData, setPageData, fetchData } = useFetchData();
  const [cardsMap, setCardsMap] = useState<Map<string, any>>(new Map());
  const innerActions = useFormatInnerActions();
  const { printTableRef, handlePrint } = usePrint();
  const refreshData = useRefreshData(fetchData);
  const [state, dispatch] = useActionReducer({
    handlePrint,
    modalRef,
    tableCacheRef,
  });
  const primaryKey = useMemo(() => {
    return pageData.primary ?? 'id';
  }, [pageData]);

  const pagination: PaginationProps = usePagination({
    ...searchRef.current.pageInfo,
    total: pageData.total,
    showLessItems: true,
    showQuickJumper: true,
    ...(props.pagination || {})
  });

  const placeConfig = useMemo(() => {
    const title = (attrs?.find(
      (attr: { placeKey: string }) => attr.placeKey === TmplPlaceConfigKey.title,
    ) || {}) as ItemData;
    const img = (attrs?.find(
      (attr: { placeKey: string }) =>
        TmplPlaceConfigKey?.img && attr.placeKey === TmplPlaceConfigKey?.img,
    ) || {}) as ItemData;
    let dataItems = attrs?.filter(
      (attr: { placeKey: string }) =>
        ![TmplPlaceConfigKey?.title, TmplPlaceConfigKey?.img]
          .filter((key) => key)
          .includes(attr?.placeKey as string),
    ) as ItemData[];
    dataItems = dataItems.filter((attr) => {
      if (attr.typeValue == 'array') {
        return !!attr.children?.length;
      }
      return attr?.propName && attr.propName != '';
    });
    return {
      title,
      img,
      dataItems,
    };
  }, [attrs]);

  const cardPrintColumns = useFormatCardColumns(placeConfig);

  const customConfig = useMemo(() => {
    let obj = {};
    attrs.forEach((attr: any) => {
      obj[attr.placeKey] = { ...attr };
    });
    return obj;
  }, [attrs]);

  const onPageChange = (pageParam: PageInfo) => {
    searchRef.current = {
      ...searchRef.current,
      iConditions: {
        ...(searchRef.current?.iConditions ?? {}),
        pageSize: pageParam.pageSize,
        pageIndex: pageParam.current,
      },
      pageInfo: {
        ...pageParam
      },
    };
    fetchData();
  };

  const loadData = (key?: string) => {
    fetchData();
  };

  const handleSelect = (key: string, row: any) => {
    const current = searchRef.current.pageInfo?.current || 1;
    const _row = { ...row, current };
    for (const value of cardsMap.values()) {
      if (current !== value.current) {
        cardsMap.clear();
        break;
      }
    }
    if (cardsMap.has(key)) {
      cardsMap.delete(key);
    } else {
      cardsMap.set(key, _row);
    }
    tableCacheRef.current.keyList = Array.from(cardsMap.keys());
    setCardsMap(new Map(cardsMap));
  };

  const onResize = () => {
    window.requestAnimationFrame(() => {
      const windowHeight = window.innerHeight;
      const topHeight = inbizTableRef.current?.querySelector?.('.inbiz-table-top-container')?.clientHeight || 0;
      const paginHeight = inbizTableRef.current?.querySelector?.('.inbiz-pagination')?.clientHeight || 0;
      const inModal = isTableInModal(cardBoxRef.current);
      // 卡片视图暂时只支持非弹框场景，后续可能会调整计算逻辑
      if (!inModal && showHeightRule == 'fixed' && showPage) {
        if (cardBoxRef.current) {
          const cardHeight = windowHeight-topHeight-paginHeight-height-boxPadding-boxMargin-16
          cardBoxRef.current.style.height = `${cardHeight}px`
          cardBoxRef.current.style.overflow = 'auto'
        }
      }
    })
  };

  const renderContent = useCallback(
    (row, actions) => {
      const actionsNode = actions?.length ? (
        <DropDownActions actions={actions} data={row}>
          <InbizIcon type="icon-more1" />
        </DropDownActions>
      ) : null;
      // tmplNode.id 存在时，并且 tmplNode.id 等于 default 执行 或者当 tmplNode 不存在或者 tmplNode.id不存在的时候执行
      const builtInTmplArr = Object.keys(builtInTmpl);
      if (!tmplNode?.id || builtInTmplArr.includes(tmplNode?.id)) {
        return (
          <CardContent
            key={row.id}
            record={row}
            config={placeConfig}
            actions={actions}
            tmplNodeId={tmplNode?.id}
            cardsMap={cardsMap}
            checkboxNode={
              rowSelection && (
                <Checkbox
                  checked={cardsMap.has(row.id)}
                  onChange={() => handleSelect(row.id, row)}
                  disabled={viewMode=='look'?true:false}
                />
              )
            }
            viewMode={viewMode}
          />
        );
      }
      return (
        <React.Fragment key={row.id}>
          {tmplNode?.node.default?.(
            {
              record: row,
              config: customConfig,
              actionProps: {
                defaultNode: actionsNode,
                dispatch,
                actions,
              },
            },
            emit,
          )}
        </React.Fragment>
      );
    },
    [tmplNode],
  );

  useImperativeHandle(
    ref,
    () => ({
      ...api(eventsRef, {
        modelname: props?.modelname || '',
        searchRef,
        tableCacheRef,
        modalRef,
        primaryKey,
        pageData,
        setPageData,
        fetchData,
        dispatch,
      }),
    }),
    [pageData],
  );

  useEffect(() => {
    window.addEventListener('resize', onResize);
    if (autoLoad) {
      fetchData();
    }
    return () => {
      window.removeEventListener('resize', onResize);
    }
  }, []);

  useEffect(() => {
    tableCacheRef.current = {
      ...tableCacheRef.current,
      data: pageData.data,
      total: pageData.total,
      refresh: fetchData,
      loadData: loadData,
      primaryKey,
      ...searchRef.current,
    };
  });
  const getLang = useMemo(() => {
    const _lang = GlobalRegistry.getDesignerLanguage();
    return commonLang[_lang?.toLocaleLowerCase()?.replace('-', '_') as keyof typeof commonLang || 'zh_cn'];
  }, [GlobalRegistry.getDesignerLanguage()]);

  return (
    <div>
      <TableCtx.Provider
        value={
          {
            state,
            tableCacheRef,
            rowSelection,
            cardsMap,
            conditions: searchRef.current?.conditions?.[0],
            emit,
            dispatch,
          } as unknown as TableCtxType
        }
      >
        <ConfigProvider locale={getLang}>
          <ResizeObserver onResize={onResize}>
          
          <div>
          <TableTop searchNode={<Search fetchData={fetchData} />} />
          <Spin spinning={loading}>
            {attrs.length > 0 && (
              <div className={cls(boxPrefixCls)} ref={cardBoxRef}>
                <div className={cls(listPrefixCls)}>
                  {pageData.data?.length ? (
                    <>
                      {pageData.data?.map((row, index) => {
                        const actions = (eventsRef?.current.onOperateColumnFormat?.(
                          innerActions,
                          row,
                          index,
                        ) ?? innerActions) as ActionConfigType[];
                        const leftActions = actions?.map((ele) => {
                          return {
                            ...ele,
                            ...hasAuth(
                              {
                                table: [{ ...ele, operationType: ele.actionType }],
                                auth: props?.columnConfig?.auth,
                              },
                              ele.actionType,
                              props.inbiz?.auth,
                            ),
                          };
                        });
                        const leftAuthActions = leftActions?.filter((ele) => ele.auth);
                        return renderContent(row, leftAuthActions);
                      })}
                      {emptyArr.map((item, index) => (
                        <div className={cls(emptyDivPrefixCls)} key={index}></div>
                      ))}
                    </>
                  ) : (
                    !loading && (
                      <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} style={{ margin: 'auto' }} />
                    )
                  )}
                </div>
              </div>
            )}
          </Spin>
          {showPage&&viewMode!='look' && pageData?.data?.length ? (
            <Pagination
              pagination={pagination}
              onPageChange={onPageChange}
              refreshData={refreshData}
              pageRefresh={pageRefresh}
            />
          ) : null}
          </div>
          
          </ResizeObserver>
        </ConfigProvider>
        <TableModal ref={modalRef} state={state} primaryKey={primaryKey} />
      </TableCtx.Provider>
      <PrintTable
        ref={printTableRef}
        style={{ display: 'none' }}
        columns={cardPrintColumns}
        dataSource={pageData.data}
        size="middle"
      />
    </div>
  );
};

export default React.forwardRef(TableCard);
